const x_offset = 300
const y_offset = 100

let y_cucc = 0

function handleModel(model: any): any[] {
  if (model == null) {
    return []
  }

  const UMLClassData: any[] = []
  const modelTemp = {
    id: model.UUID,
    shape: 'class',
    name: [model.name],
    attributes: [
      `lowerMultiplicity = ${model.lowerMultiplicity}`,
      `upperMultiplicity = ${model.upperMultiplicity}`
    ],
    type: 'model',
    position: {
      x: 0,
      y: 0
    }
  }

  UMLClassData.push(modelTemp)

  handleContainers(UMLClassData, model.containers, modelTemp.id, 1)

  return UMLClassData
}
function handleContainers(
  UMLClassData: any[],
  containers: any,
  sourceId: string,
  level: number
): void {
  if (containers == null) {
    return
  }

  for (let index = 0; index < containers.length; index++) {
    const element = containers[index]

    if (index !== 0) {
      y_cucc += y_offset
    }
    const containerNode = {
      id: element.UUID,
      shape: 'class',
      name: [element.name],
      attributes: [
        `lowerMultiplicity = ${element.lowerMultiplicity}`,
        `upperMultiplicity = ${element.upperMultiplicity}`
      ],
      type: 'container',
      isNew: element.isNew,
      position: {
        x: x_offset * level,
        y: y_cucc
      }
    }

    const containerEdge = {
      id: `${containerNode.id}2${sourceId}`,
      shape: 'composition',
      source: sourceId,
      target: containerNode.id,
      label: '+container'
    }
    UMLClassData.push(containerNode)
    UMLClassData.push(containerEdge)

    handleSubContainers(
      UMLClassData,
      element.subContainers,
      element.UUID,
      level + 1
    )
    handleParameters(UMLClassData, element.parameters, element.UUID, level + 1)
    handleReferences(UMLClassData, element.references, element.UUID, level + 1)
  }
}

function handleSubContainers(
  UMLClassData: any[],
  subContainers: any,
  sourceId: string,
  level: number
): void {
  if (subContainers == null) {
    return
  }
  subContainers.forEach((element: any, index: number) => {
    if (index !== 0) {
      y_cucc += y_offset
    }

    const subcontainerNode = {
      id: element.UUID,
      shape: 'class',
      name: [element.name],
      attributes: [
        `lowerMultiplicity = ${element.lowerMultiplicity}`,
        `upperMultiplicity = ${element.upperMultiplicity}`
      ],
      type: 'subContainer',
      isNew: element.isNew,
      position: {
        x: x_offset * level,
        y: y_cucc
      }
    }

    const subcontainerEdge = {
      id: `${subcontainerNode.id}2${sourceId}`,
      shape: 'composition',
      source: sourceId,
      target: subcontainerNode.id,
      label: '+subContainer'
    }

    UMLClassData.push(subcontainerNode)
    UMLClassData.push(subcontainerEdge)

    handleSubContainers(
      UMLClassData,
      element.subContainers,
      element.UUID,
      level + 1
    )
    handleParameters(UMLClassData, element.parameters, element.UUID, level + 1)
    handleReferences(UMLClassData, element.references, element.UUID, level + 1)
  })
}

function handleParameters(
  UMLClassData: any[],
  parameters: any,
  sourceId: string,
  level: number
): void {
  if (parameters == null) {
    return
  }

  for (let index = 0; index < parameters.length; index++) {
    const element = parameters[index]

    if (index !== 0) {
      y_cucc += y_offset
    }
    const parameterNode = {
      id: element.UUID,
      shape: 'class',
      name: [element.name],
      attributes: [
        `lowerMultiplicity = ${element.lowerMultiplicity}`,
        `upperMultiplicity = ${element.upperMultiplicity}`,
        `defaultValue = ${element.defaultValue}`
      ],
      type: 'parameter',
      isNew: element.isNew,
      parameterType: element.type,
      position: {
        x: x_offset * level,
        y: y_cucc
      }
    }

    if (element.type === 'integer' || element.type === 'float') {
      parameterNode.attributes.push(`max = ${element.max}`)
      parameterNode.attributes.push(`min = ${element.min}`)
    }

    const parameterEdge = {
      id: `${parameterNode.id}2${sourceId}`,
      shape: 'composition',
      source: sourceId,
      target: parameterNode.id,
      label: '+parameter'
    }
    UMLClassData.push(parameterNode)
    UMLClassData.push(parameterEdge)

    // if (element.type === 'enumeration') {
    //   handleLiterals(
    //     UMLClassData,
    //     element.literals,
    //     parameterNode.id,
    //     level + 1
    //   )
    // }
  }
}
function handleReferences(
  UMLClassData: any[],
  references: any,
  sourceId: string,
  level: number
): void {
  if (references == null) {
    return
  }

  for (let index = 0; index < references.length; index++) {
    const element = references[index]

    if (index !== 0) {
      y_cucc += y_offset
    }

    const referenceNode = {
      id: element.UUID,
      shape: 'class',
      name: [element.name],
      attributes: [
        `lowerMultiplicity = ${element.lowerMultiplicity}`,
        `upperMultiplicity = ${element.upperMultiplicity}`,
        `defaultValue = ${element.defaultValue}`
      ],
      type: 'reference',
      isNew: element.isNew,
      referenceType: element.type,
      position: {
        x: x_offset * level,
        y: y_cucc
      }
    }

    const referenceEdge = {
      id: `${referenceNode.id}2${sourceId}`,
      shape: 'composition',
      source: sourceId,
      target: referenceNode.id,
      label: '+reference'
    }
    UMLClassData.push(referenceNode)
    UMLClassData.push(referenceEdge)

    handleDestination(
      UMLClassData,
      element.destinations,
      referenceNode.id,
      level + 1
    )
  }
}
function handleLiterals(
  UMLClassData: any[],
  literals: any,
  sourceId: string,
  level: number
): void {
  if (literals == null) {
    return
  }

  for (let index = 0; index < literals.length; index++) {
    const element = literals[index]

    if (index !== 0) {
      y_cucc += y_offset
    }

    const literalNode = {
      id: element.UUID,
      shape: 'class',
      name: [element.name],
      type: 'literal',
      isNew: element.isNew,
      position: {
        x: x_offset * level,
        y: y_cucc
      }
    }

    const literalEdge = {
      id: `${literalNode.id}2${sourceId}`,
      shape: 'composition',
      source: sourceId,
      target: literalNode.id,
      label: '+literal'
    }
    UMLClassData.push(literalNode)
    UMLClassData.push(literalEdge)
  }
}
function handleDestination(
  UMLClassData: any[],
  destinations: any,
  sourceId: string,
  level: number
): void {
  if (destinations == null) {
    return
  }

  for (let index = 0; index < destinations.length; index++) {
    const element = destinations[index]

    if (index !== 0) {
      y_cucc += y_offset
    }

    const destinationNode = {
      id: element.UUID,
      shape: 'class',
      name: [element.name],
      type: 'destination',
      isNew: element.isNew,
      position: {
        x: x_offset * level,
        y: y_cucc
      }
    }
    const destinationEdge = {
      id: `${destinationNode.id}2${sourceId}`,
      shape: 'composition',
      source: sourceId,
      target: destinationNode.id,
      label: '+destination'
    }
    UMLClassData.push(destinationNode)
    UMLClassData.push(destinationEdge)
  }
}

export default handleModel
